﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;

using global::NHibernate.Linq;
using ICriteria = global::NHibernate.ICriteria;
using ISession = global::NHibernate.ISession;
using ITransaction = global::NHibernate.ITransaction;

using MI.Entity;
using MI.ORM.IDAL;
using NHibernate;
using System.Linq.Expressions;

namespace MI.ORM.DAL
{
    public class Database : Disposable,IDatabase
    {
        private readonly ISession session;

        //private readonly ICollection<IEntity> transientEntities;

        private ITransaction transaction;

        public Database(ISessionFactory sessionFactory)
        {
            this.session = sessionFactory.OpenSession();
        }

        public virtual IQueryable<T> All<T>() where T:class
        {
            return session.Query<T>();
        }

        public virtual ICriteria CreateCriteria<T>() where T:class
        {
            return session.CreateCriteria<T>();
        }

        public virtual IQueryable<T> FilterBy<T>(Expression<Func<T, bool>> expression) where T : class
        {
            return All<T>().Where(expression).AsQueryable();
        }

        public virtual void Add<T>(T entity) where T : class
        {
            try
            {
                EnsureTransaction();
                session.Save(entity);
                //transientEntities.Add(entity);
            }
            catch
            {
                transaction.Rollback();
                //transientEntities.Clear();
                throw;
            }
        }

        public virtual void Update<T>(T entity) where T : class
        {
            try
            {
                EnsureTransaction();
                session.Update(entity);
            }
            catch
            {
                transaction.Rollback();
                //transientEntities.Clear();
            }
        }

        public virtual void Delete<T>(T entity) where T : class
        {
            try
            {
                EnsureTransaction();
                //var item = this.GetById(entity.Id);
                session.Delete(entity);
            }
            catch
            {
                transaction.Rollback();
                throw;
            }
        }

        public virtual void Commit()
        {
            EnsureTransaction();
            try
            {
                //transientEntities.Each(e => session.Save(e));
                transaction.Commit();
                //transientEntities.Clear();
            }
            catch
            {
                transaction.Rollback();
                //transientEntities.Clear();
                throw;
            }
        }

        protected override void DisposeCore()
        {
            //transientEntities.Clear();
            if (transaction != null)
            {
                if (transaction.IsActive)
                {
                    transaction.Rollback();
                }

                transaction.Dispose();
                transaction = null;
            }

            if (session != null)
            {
                if (session.IsOpen)
                {
                    session.Close();
                }

                session.Dispose();
            }
        }

        private void EnsureTransaction()
        {
            if (transaction == null || !transaction.IsActive || transaction.WasCommitted || transaction.WasRolledBack)
            {
                transaction = session.BeginTransaction();
            }
        }
    }
}
